#include "pch.h"

#include "math/line2.h"



namespace Math
{

	///
	line2::line2():
m_origin(0.0f, 0.0f),
	m_direction(0.0f,0.0f)
{

}


///
line2::line2(const Math::point2 & p, const Math::vector2 & d):
m_origin(p),
	m_direction(d)
{

}


///
line2::line2(const Math::point2 & p1, const Math::point2 & p2):
m_origin(p1),
	m_direction(p2-p1)
{

}


///
line2::line2(const Math::line2 & rhs):
m_origin(rhs.m_origin),
	m_direction(rhs.m_direction)
{

}



///
void line2::operator = (const Math::line2 & rhs)
{
	this->m_origin = rhs.m_origin;

	this->m_direction = rhs.m_direction;
}


///
bool line2::operator == (const Math::line2 & rhs) const 
{
	return ((this->m_direction == rhs.m_direction) && (this->m_origin == rhs.m_origin));
}


///
bool line2::operator != (const Math::line2 & rhs) const 
{
	return ((this->m_direction != rhs.m_direction) || (this->m_origin != rhs.m_origin));
}



///
scalar line2::length() const 
{
	return this->m_direction.length();;
}


///
scalar line2::lengthsq() const
{
	return this->m_direction.lengthsq();
}

///
scalar line2::distance(const Math::point2 &p) const
{
	Math::float2 difference(p - this->m_origin);

	scalar s = this->m_direction.getx() * this->m_direction.getx() + this->m_direction.gety() * this->m_direction.gety();

	if(s > 0.0f)
	{
		scalar t = this->m_direction.getx() * difference.getx() + this->m_direction.gety() * difference.gety();

		difference = difference - this->m_direction * t;

		return difference.length();
	}
	else
	{
		Math::float2 temp(p - this->m_origin);

		return temp.length();
	}
}



///
void line2::set(const Math::point2 &p, const Math::vector2 &d)
{
	this->m_origin = p;

	this->m_direction = d;
}


///
void line2::set(const Math::point2 &p1, const Math::point2 &p2)
{
	this->m_origin = p1;

	this->m_direction = p2 - p1;
}


///
const Math::point2 & line2::getstart() const 
{
	return this->m_origin;
}


///
Math::point2 line2::getend() const 
{
	return (this->m_origin + this->m_direction);
}



///
bool line2::intersectline(const Math::point2 &p) const
{
	Math::float2 temp(p - this->m_origin);

	if(float2::normalize(temp) == float2::normalize(this->m_direction))
		return true;
	else
		return false;
}


///
bool line2::intersectline(const Math::line2 &l) const
{
	scalar x1 = this->getstart().getx();
	scalar x2 = this->getend().getx();
	scalar x3 = l.getstart().getx();
	scalar x4 = l.getend().getx();

	scalar y1 = this->getstart().gety();
	scalar y2 = this->getend().gety();
	scalar y3 = l.getstart().gety();
	scalar y4 = l.getend().gety();

	scalar det = (x1 - x2)*(y3-y4)-(y1-y2)*(x3-x4);

	if(det == 0.0f)
		return false;
	else
		return true;
}


///
scalar line2::getclosestpoint_t(const Math::point2 & p) const 
{
	Math::vector2 difference(p - this->m_origin);

	scalar s = this->m_direction.getx() * this->m_direction.getx() + this->m_direction.gety() * this->m_direction.gety();

	if(s > 0.0f)
		return this->m_direction.getx() * difference.getx() + this->m_direction.gety() * difference.gety();
	else
		return 0.0f;
}


///
Math::point2 line2::getclosestpoint(const Math::point2 & p) const
{
	Math::vector2 difference(p - this->m_origin);

	scalar s = this->m_direction.getx() * this->m_direction.getx() + this->m_direction.gety() * this->m_direction.gety();

	if(s > 0.0f)
		return this->getpointat(this->m_direction.getx() * difference.getx() + this->m_direction.gety() * difference.gety());
	else
		return this->getstart();
}


///
Math::point2 line2::getpointat(scalar t) const 
{
	return this->m_origin + this->m_direction * t;
}

}